home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / sun4.md / devXbus.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  28KB  |  1,002 lines

  1. /* 
  2.  * devXbus.c --
  3.  *
  4.  *    Routines used for running the xbus board that the RAID project
  5.  *    built.
  6.  *
  7.  * Copyright 1991 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/sun4.md/devXbus.c,v 9.3 92/10/23 15:04:43 elm Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include "sprite.h"
  22. #include "stdio.h"
  23. #include "mach.h"
  24. #include "dev.h"
  25. #include "devInt.h"
  26. #include "stdlib.h"
  27. #include "vmMach.h"
  28. #include "dev/xbus.h"
  29. #include "devXbusInt.h"
  30. #include "devXbus.h"
  31. #include "dbg.h"
  32. #include "sync.h"
  33.  
  34. int        devXbusDebug = FALSE;
  35. static int        devXbusModuleInitted = FALSE;
  36. static DevXbusInfo    *xbusInfo[DEV_XBUS_MAX_BOARDS];
  37. static Sync_Condition    xorTestDone;
  38.  
  39.  
  40. /*----------------------------------------------------------------------
  41.  *
  42.  * DevXbusResetBoard
  43.  *
  44.  *    Reset the xbus board by poking the reset registers.  Get the
  45.  *    mutex semaphore first, though.
  46.  *
  47.  *----------------------------------------------------------------------
  48.  */
  49. static
  50. ReturnStatus
  51. DevXbusResetBoard (infoPtr)
  52. DevXbusInfo*    infoPtr;
  53. {
  54.     ReturnStatus status = SUCCESS;
  55.     DevXbusCtrlRegs *regPtr = infoPtr->regs;
  56.     unsigned int resetValue;
  57.  
  58.     if (devXbusDebug) {
  59.     printf ("DevXbusResetBoard: resetting %s.\n", infoPtr->name);
  60.     }
  61.     resetValue = DEV_XBUS_RESETREG_RESET;
  62.     status = Mach_Probe (sizeof (regPtr->reset),(Address)&resetValue,
  63.              (Address)&(regPtr->reset));
  64.              
  65.     if (status != SUCCESS) {
  66.     goto resetDone;
  67.     }
  68.     MACH_DELAY (500000);
  69.     resetValue = infoPtr->resetValue;
  70.     status = Mach_Probe (sizeof (regPtr->reset), (Address)&resetValue,
  71.              (Address)&(regPtr->reset));
  72.  
  73.     MASTER_LOCK (&infoPtr->mutex);
  74.     infoPtr->qHead = infoPtr->qTail = infoPtr->xorQueue;
  75.     infoPtr->qEnd = &(infoPtr->xorQueue[DEV_XBUS_MAX_XOR_BUFS]);
  76.     infoPtr->numInQ = 0;
  77.     infoPtr->state = DEV_XBUS_STATE_OK;
  78.   resetDone:
  79.     MASTER_UNLOCK (&infoPtr->mutex);
  80.     if (devXbusDebug) {
  81.     printf ("DevXbusResetBoard: done, status = 0x%x\n", status);
  82.     }
  83.     return (status);
  84. }
  85.  
  86.  
  87. /*
  88.  *----------------------------------------------------------------------
  89.  *
  90.  * DevXbusInit
  91.  *
  92.  *    Initialize the xbus board and set up necessary data structures.
  93.  *
  94.  *----------------------------------------------------------------------
  95.  */
  96. ENTRY ClientData
  97. DevXbusInit (ctrlPtr)
  98. DevConfigController *ctrlPtr;
  99. {
  100.     ReturnStatus    status = SUCCESS;
  101.     DevXbusInfo*    infoPtr = NULL;
  102.     DevXbusCtrlRegs*    regPtr = (DevXbusCtrlRegs *)ctrlPtr->address;
  103.     int            boardNum;
  104.     unsigned int    resetVal;
  105.     int            i;
  106.  
  107.     boardNum = ctrlPtr->controllerID;
  108.     if (!devXbusModuleInitted) {
  109.     int i;
  110.     for (i = 0; i < DEV_XBUS_MAX_BOARDS; i++) {
  111.         xbusInfo[i] = NULL;
  112.     }
  113.     devXbusModuleInitted = TRUE;
  114.     }
  115.  
  116.     if (boardNum >= DEV_XBUS_MAX_BOARDS) {
  117.     status = DEV_NO_DEVICE;
  118.     goto initExit;
  119.     }
  120.  
  121.     /*
  122.      * Try to find the board by probing the reset register.
  123.      */
  124.     resetVal = DEV_XBUS_RESETREG_RESET;
  125.     if ((status = Mach_Probe (sizeof (regPtr->reset), (char*)&resetVal,
  126.                   (char*)&(regPtr->reset))) != SUCCESS) {
  127.     if (devXbusDebug) {
  128.         printf ("DevXbusInit: %s not responding to probe.\n",
  129.             ctrlPtr->name);
  130.     }
  131.     goto initExit;
  132.     }
  133.  
  134.     if ((infoPtr = (DevXbusInfo *) malloc (sizeof (DevXbusInfo))) == NULL) {
  135.     printf ("DevXbusInit: Couldn't allocate space for board info.\n");
  136.     status = FAILURE;
  137.     goto initExit;
  138.     }
  139.  
  140.     xbusInfo[boardNum] = infoPtr;
  141.     infoPtr->regs = regPtr;
  142.     infoPtr->state = 0;
  143.     infoPtr->name = ctrlPtr->name;
  144.     infoPtr->addressBase = Dev_XbusAddressBase (boardNum);
  145.     infoPtr->boardId = boardNum;
  146.     infoPtr->resetValue = DEV_XBUS_RESETREG_NORMAL;
  147.     for (i = 0; i < DEV_XBUS_MALLOC_NUM_SIZES; i++) {
  148.     infoPtr->freeList[i] = NULL;
  149.     }
  150.     infoPtr->freePtrList = NULL;
  151.  
  152.     if ((infoPtr->hippisCtrlFifo = (vuint *)VmMach_MapInDevice
  153.      ((Address)(infoPtr->addressBase + DEV_XBUS_REG_HIPPIS_CTRL_FIFO),
  154.       DEV_XBUS_ADDR_SPACE)) == NULL) {
  155.     if (devXbusDebug) {
  156.         printf ("%s couldn't map in hippis fifo.\n", ctrlPtr->name);
  157.     }
  158.     status = FAILURE;
  159.     goto initExit;
  160.     }
  161.     if ((infoPtr->hippidCtrlFifo = (vuint *)VmMach_MapInDevice
  162.      ((Address)(infoPtr->addressBase + DEV_XBUS_REG_HIPPID_CTRL_FIFO),
  163.       DEV_XBUS_ADDR_SPACE)) == NULL) {
  164.     if (devXbusDebug) {
  165.         printf ("%s couldn't map in hippid fifo.\n", ctrlPtr->name);
  166.     }
  167.     status = FAILURE;
  168.     goto initExit;
  169.     }
  170.     if ((infoPtr->xorCtrlFifo = (vuint *)VmMach_MapInDevice
  171.      ((Address)(infoPtr->addressBase + DEV_XBUS_REG_XOR_CTRL_FIFO),
  172.       DEV_XBUS_ADDR_SPACE)) == NULL) {
  173.     if (devXbusDebug) {
  174.         printf ("%s couldn't map in xor fifo.\n", ctrlPtr->name);
  175.     }
  176.     status = FAILURE;
  177.     goto initExit;
  178.     }
  179.  
  180.     sprintf (infoPtr->semName, "XbusMutex 0x%x", boardNum);
  181.     Sync_SemInitDynamic (&infoPtr->mutex, infoPtr->semName);
  182.     status = DevXbusResetBoard (infoPtr);
  183.     if (status == SUCCESS) {
  184.     infoPtr->state |= DEV_XBUS_STATE_OK;
  185.     } else {
  186.     status = DEV_NO_DEVICE;
  187.     }
  188.  
  189.   initExit:
  190.     if (status != SUCCESS) {
  191.     printf ("DevXbusInit: Didn't find %s at at 0x%x\n", ctrlPtr->name,
  192.         Dev_XbusAddressBase(boardNum));
  193.     } else {
  194.     printf ("Found %s (xbus%d) at 0x%x\n", ctrlPtr->name,
  195.         boardNum, infoPtr->addressBase);
  196.     }
  197.     return ((status == SUCCESS) ? (ClientData)infoPtr : DEV_NO_CONTROLLER);
  198. }
  199.  
  200. /*----------------------------------------------------------------------
  201.  *
  202.  * DevXbusStuffXor --
  203.  *
  204.  *    This procedure tries to stuff an XOR command into the xbus
  205.  *    board.  It will only do so if there isn't already an XOR
  206.  *    in progress.  The master lock for this xbus *must* be held
  207.  *    when this is called.
  208.  *
  209.  *----------------------------------------------------------------------
  210.  */
  211. static
  212. void
  213. DevXbusStuffXor (infoPtr)
  214. register DevXbusInfo*    infoPtr;
  215. {
  216.     register int        i;
  217.     register DevXbusXorInfo*    xorPtr;
  218.     register unsigned int*    curAddrPtr;
  219.  
  220.     if (devXbusDebug) {
  221.     printf ("DevXbusStuffXor: stuffing %s, %d in queue.\n", infoPtr->name,
  222.         infoPtr->numInQ);
  223.     }
  224.     if (!(infoPtr->state & DEV_XBUS_STATE_XOR_GOING) &&
  225.     (infoPtr->numInQ != 0)) {
  226.     infoPtr->state |= DEV_XBUS_STATE_XOR_GOING;
  227.     xorPtr = infoPtr->qHead;
  228.     /*
  229.      * XOR buffer size and buffer address are passed as long words.
  230.      * This means they must all be shifted right two bits.
  231.      */
  232.     *(infoPtr->xorCtrlFifo) = xorPtr->bufLen >> 2;
  233.     for (i = 0, curAddrPtr = xorPtr->buf; i < xorPtr->numBufs; i++) {
  234.         *(infoPtr->xorCtrlFifo) = *(curAddrPtr++) >> 2;
  235.     }
  236.     *(infoPtr->xorCtrlFifo) = (xorPtr->destBuf >> 2) | DEV_XBUS_XOR_GO;
  237.     }
  238.     if (devXbusDebug) {
  239.     printf ("DevXbusStuffXor: exiting...\n");
  240.     }
  241. }
  242.  
  243. /*----------------------------------------------------------------------
  244.  *
  245.  * accessXbusRegister
  246.  *
  247.  *    Read or write an xbus board register.  By design, the register
  248.  *    symbol is the offset from the start of the register area.
  249.  *    Treat the FIFO registers separately, as they might not be
  250.  *    contiguously mapped with the rest of the registers.
  251.  *
  252.  *----------------------------------------------------------------------
  253.  */
  254. static
  255. ReturnStatus
  256. accessXbusRegister (infoPtr, regNum, valuePtr, accessType)
  257. DevXbusInfo    *infoPtr;
  258. int        regNum;
  259. unsigned int*    valuePtr;
  260. int        accessType;
  261. {
  262.     ReturnStatus    status = SUCCESS;
  263.     Address        regAddr;
  264.  
  265.     switch (regNum) {
  266.       case DEV_XBUS_REG_HIPPID_CTRL_FIFO:
  267.     regAddr = (Address)infoPtr->hippidCtrlFifo;
  268.     break;
  269.       case DEV_XBUS_REG_HIPPIS_CTRL_FIFO:
  270.     regAddr = (Address)infoPtr->hippisCtrlFifo;
  271.     break;
  272.       case DEV_XBUS_REG_XOR_CTRL_FIFO:
  273.     regAddr = (Address)infoPtr->xorCtrlFifo;
  274.     break;
  275.       default:
  276.     if ((regNum >= 0) && (regNum <= DEV_XBUS_REG_STATUS)) {
  277.         regAddr = (Address)infoPtr->regs + regNum;
  278.     } else {
  279.         status = GEN_INVALID_ARG;
  280.         goto endAccess;
  281.     }
  282.     }
  283.  
  284.     if (accessType == IOC_XBUS_READ_REG) {
  285.     status = Mach_Probe (sizeof (*valuePtr), regAddr, (Address)valuePtr);
  286.     } else if (accessType == IOC_XBUS_WRITE_REG) {
  287.     status = Mach_Probe (sizeof (*valuePtr), (Address)valuePtr, regAddr);
  288.     } else {
  289.     status = GEN_INVALID_ARG;
  290.     }
  291.   endAccess:
  292.     return (status);
  293. }
  294.  
  295. /*----------------------------------------------------------------------
  296.  *
  297.  * DevXbusXor --
  298.  *
  299.  *    This is the internally callable xor queueing routine.  It assumes
  300.  *    that the master lock is held before the routine is called.
  301.  *
  302.  * Returns:
  303.  *    Standard Sprite status.
  304.  * Side effects:
  305.  *
  306.  *----------------------------------------------------------------------
  307.  */
  308. static
  309. ReturnStatus
  310. DevXbusXor (infoPtr, destBuf, numBufs, bufArrayPtr, bufLen, callbackProc,
  311.         clientData)
  312. DevXbusInfo*    infoPtr;
  313. unsigned int    destBuf;
  314. unsigned int    numBufs;    
  315. unsigned int*     bufArrayPtr;
  316. unsigned int    bufLen;
  317. void        (*callbackProc)();
  318. ClientData    clientData;
  319. {
  320.     ReturnStatus    status = SUCCESS;
  321.     DevXbusXorInfo*    xorPtr;
  322.     unsigned int*    bufCopyPtr;
  323.     unsigned int    i;
  324.  
  325.     if (infoPtr->numInQ == DEV_XBUS_MAX_QUEUED_XORS) {
  326.     status = FAILURE;
  327.     if (devXbusDebug) {
  328.         printf ("Dev_XbusXor: XOR queue for %s full.\n", infoPtr->name);
  329.     }
  330.     } else if (numBufs > DEV_XBUS_MAX_XOR_BUFS) {
  331.     status = GEN_INVALID_ARG;
  332.     } else {
  333.     xorPtr = infoPtr->qTail;
  334.     infoPtr->qTail += 1;
  335.     if (infoPtr->qTail == infoPtr->qEnd) {
  336.         infoPtr->qTail = infoPtr->xorQueue;
  337.     }
  338.     infoPtr->numInQ += 1;
  339.     if (devXbusDebug) {
  340.         printf ("Dev_XbusXor: %s added XOR in position %d.\n",
  341.             infoPtr->name, infoPtr->qTail - infoPtr->xorQueue);
  342.         printf ("num bufs = 0x%x, dest buf: 0x%x\n", numBufs,
  343.             destBuf);
  344.     }
  345.     xorPtr->destBuf = destBuf;
  346.     for (i = 0, bufCopyPtr = xorPtr->buf; i < numBufs; i++) {
  347.         if (devXbusDebug) {
  348.         printf ("Src buffer at 0x%x\n", *bufArrayPtr);
  349.         }
  350.         *(bufCopyPtr++) = *(bufArrayPtr++);
  351.     }
  352.     xorPtr->callbackProc = callbackProc;
  353.     xorPtr->clientData = clientData;
  354.     xorPtr->bufLen = bufLen;
  355.     xorPtr->numBufs = numBufs;
  356.     xorPtr->status = SUCCESS;
  357.     DevXbusStuffXor (infoPtr);
  358.     }
  359.  
  360.     return (status);
  361. }
  362.  
  363. /*----------------------------------------------------------------------
  364.  *
  365.  * Dev_XbusXor
  366.  *
  367.  *    Queue up an XOR for the xbus board.  The callback routine will
  368.  *    get called with client data after the XOR completes.  Since the
  369.  *    callback may get called directly from interrupt level, it MUST
  370.  *    follow all guidelines for interrupt-time routines.  It should
  371.  *    also be short.
  372.  *
  373.  *    The bufArrayPtr should point to an array of addresses to XOR.
  374.  *    The first address will be the destination, and the remainder
  375.  *    (there should be numBuffers) will be the sources.
  376.  *
  377.  * Returns:
  378.  *    Standard Sprite return status.
  379.  * Side effects:
  380.  *    none
  381.  *
  382.  *----------------------------------------------------------------------
  383.  */
  384. ENTRY ReturnStatus
  385. Dev_XbusXor (boardId, destBuf, numBufs, bufArrayPtr, bufLen,
  386.          callbackProc, clientData)
  387. unsigned int    boardId;
  388. unsigned int    destBuf;
  389. unsigned int    numBufs;
  390. unsigned int*     bufArrayPtr;
  391. unsigned int    bufLen;
  392. void        (*callbackProc)();
  393. ClientData    clientData;
  394. {
  395.     ReturnStatus    status = SUCCESS;
  396.     DevXbusInfo*    infoPtr;
  397.  
  398.     if (boardId > DEV_XBUS_MAX_BOARDS) {
  399.     status = FAILURE;
  400.     goto xorExit;
  401.     }
  402.     if ((infoPtr = xbusInfo[boardId]) == NULL) {
  403.     status = FAILURE;
  404.     goto xorExit;
  405.     }
  406.  
  407.     if (devXbusDebug) {
  408.     printf ("Dev_XbusXor: about to do XOR for %s\n", infoPtr->name);
  409.     }
  410.     MASTER_LOCK (&(infoPtr->mutex));
  411.     status = DevXbusXor (infoPtr, destBuf, numBufs, bufArrayPtr, bufLen,
  412.              callbackProc, clientData);
  413.     MASTER_UNLOCK (&(infoPtr->mutex));
  414.   xorExit:
  415.     if (status != SUCCESS) {
  416.     (callbackProc)(clientData, status);
  417.     }
  418.     return (SUCCESS);
  419. }
  420.  
  421. /*----------------------------------------------------------------------
  422.  *
  423.  * xorCallback
  424.  *
  425.  *    Called back when an IOControl XOR finishes.
  426.  *
  427.  * Returns:
  428.  *    none
  429.  * Side effects:
  430.  *    Wakes up waiting XOR.
  431.  *
  432.  *----------------------------------------------------------------------
  433.  */
  434. static
  435. void
  436. xorCallback (infoPtr, status)
  437. DevXbusInfo*    infoPtr;
  438. ReturnStatus    status;
  439. {
  440.     if (devXbusDebug) {
  441.     printf ("xorCallback for %s.\n", infoPtr->name);
  442.     }
  443.  
  444.     MASTER_LOCK (&infoPtr->mutex);
  445.     infoPtr->state &= ~DEV_XBUS_STATE_XOR_TEST;
  446.     MASTER_UNLOCK (&infoPtr->mutex);
  447.     Sync_MasterBroadcast (&xorTestDone);
  448. }
  449.  
  450. #if 0
  451. /*
  452.  *----------------------------------------------------------------------
  453.  *
  454.  * makeFreeBuffer
  455.  *
  456.  *    Generate a free buffer by recursively splitting a larger buffer.
  457.  *
  458.  * Returns:
  459.  *    none
  460.  * Side effects:
  461.  *    May split larger buffers to get one of the appropriate size.
  462.  *
  463.  *----------------------------------------------------------------------
  464.  */
  465. static
  466. int
  467. makeFreeBuffer (xbusPtr, power)
  468. DevXbusInfo    *xbusPtr;
  469. int        power;
  470. {
  471.     DevXbusFreeMem    *freeMemPtr;
  472.  
  473.     if (power >= (DEV_XBUS_MALLOC_NUM_SIZES - 1)) {
  474.     /*
  475.      * Can't "manufacture" new buffers for the largest size.
  476.      */
  477.     return FALSE;
  478.     } else if (xbusPtr->freeList[power+1] == NULL) {
  479.     if (!makeFreeBuffer (xbusPtr, power+1)) {
  480.         return FALSE;
  481.     }
  482.     freeMemPtr = xbusPtr->freeList[power+1];
  483.     xbusPtr->freeList[power+1] = xbusPtr->freeList[power+1]->next;
  484.     freeAddr = freeMemPtr->address;
  485.     }
  486. }
  487.  
  488. /*
  489.  *----------------------------------------------------------------------
  490.  *
  491.  * Dev_XbusMalloc
  492.  *
  493.  *    Allocate some portion of XBUS memory and return its xbus address.
  494.  *    The requested size is rounded up to a power of 2 between 4K and
  495.  *    8 MB.
  496.  *
  497.  * Returns:
  498.  *    Address of the section of XBUS memory which was allocated.
  499.  *    -1 if there is no available memory 
  500.  * Side effects:
  501.  *    May allocate kernel memory for record-keeping.
  502.  *
  503.  *----------------------------------------------------------------------
  504.  */
  505. int
  506. Dev_XbusMalloc (boardNum, size)
  507. int    boardNum;
  508. int    size;
  509. {
  510.     int        bufSize = 1 << DEV_XBUS_MALLOC_MIN_SIZE;
  511.     int        powerCount = 0;
  512.     DevXbusInfo*    xbusPtr;
  513.     DevXbusFreeMem*    freePtr;
  514.     DevXbusFreeMem**    freeListPtr;
  515.     int        freeAddr;
  516.  
  517.     if ((xbusPtr = xbusInfo[boardNum]) == NULL) {
  518.     return -1;
  519.     }
  520.  
  521.     /*
  522.      * First, figure out how big the request is.
  523.      */
  524.     while (size > bufSize) {
  525.     bufSize <<= 1;
  526.     if (++powerCount > DEV_XBUS_MALLOC_NUM_SIZES) {
  527.         return -1;
  528.     }
  529.     }
  530.  
  531.     freeListPtr = &(xbusPtr->freeList[powerCount]);
  532.     MASTER_LOCK (&(xbusPtr->mutex));
  533.     if ((*freeListPtr == NULL) && (!makeFreeBuffer (xbusPtr, powerCount)) {
  534.         freeAddr = -1;
  535.     } else {
  536.     freePtr = *freeListPtr;
  537.     *freeListPtr = (*freeListPtr)->next;
  538.     freeAddr = freeMemPtr->address;
  539.     freeMemPtr (
  540.     freePtr->next = xbusPtr->freePtrList;
  541.     xbusPtr->freePtrList = freePtr;
  542.     }
  543.     MASTER_UNLOCK (&(xbusPtr->mutex));
  544.  
  545.     return freeAddr;
  546. }
  547.  
  548. /*
  549.  *----------------------------------------------------------------------
  550.  *
  551.  * Dev_XbusFree
  552.  *
  553.  *    Free XBUS memory previously allocated by Dev_XbusMalloc.  Note
  554.  *    that this will *NOT* combine adjacent small pieces into larger
  555.  *    pieces; fragmentation isn't dealt with.
  556.  *
  557.  * Returns:
  558.  *    none
  559.  * Side effects:
  560.  *    May allocate kernel memory for record-keeping.
  561.  *
  562.  *----------------------------------------------------------------------
  563.  */
  564. Dev_XbusFree (boardNum, size, addr)
  565. int    boardNum;
  566. int    size;
  567. unsigned int addr;
  568. {
  569. }
  570. #endif
  571.  
  572. /*
  573.  *----------------------------------------------------------------------
  574.  *
  575.  * Dev_XbusHippiBuffer
  576.  *
  577.  *    Stuff an (extent, address) pair into either the HIPPI-S or HIPPI-D
  578.  *    DMA control FIFO on the xbus board.  No locks are used.  This
  579.  *    routine is for testing purposes ONLY.
  580.  *
  581.  * Returns:
  582.  *    Standard Sprite return status.
  583.  * Side effects:
  584.  *    Causes the xbus board to transfer data to or from the HIPPI
  585.  *
  586.  *----------------------------------------------------------------------
  587.  */
  588. ReturnStatus
  589. Dev_XbusHippiBuffer (boardNum, which, size, addr)
  590. int    boardNum;
  591. int    which;        /* >0 means SRC, <0 means DST */
  592. unsigned int    size;
  593. unsigned int    addr;
  594. {
  595.     register DevXbusInfo*    xbusPtr;
  596.  
  597.     if (devXbusDebug) {
  598.     printf ("Entering Dev_XbusHippiBuffer for board %d.\n", boardNum);
  599.     }
  600.  
  601.     if ((xbusPtr = xbusInfo[boardNum]) == NULL) {
  602.     printf ("Dev_XbusHippiBuffer: invalid board number (%d).\n", boardNum);
  603.     return DEV_INVALID_UNIT;
  604.     }
  605.  
  606.     if (which > 0) {
  607.     *(xbusPtr->hippisCtrlFifo) = size >> 2;
  608.     *(xbusPtr->hippisCtrlFifo) = addr >> 2;
  609.     } else if (which < 0) {
  610.     *(xbusPtr->hippidCtrlFifo) = size >> 2;
  611.     *(xbusPtr->hippidCtrlFifo) = addr >> 2;
  612.     } else {
  613.     return (GEN_INVALID_ARG);
  614.     }
  615.     return (SUCCESS);
  616. }
  617.  
  618. /*
  619.  *----------------------------------------------------------------------
  620.  *
  621.  * DevXbusIOControl
  622.  *
  623.  *    Perform an IO control on the VME link card set.  These can
  624.  *    range from a simple remote ping to playing with the card's
  625.  *    registers such as address modifiers or window selection.
  626.  *    No attempt is made to coordinate between two processes that
  627.  *    mess up the same VME link; that may come in a future version.
  628.  *
  629.  * Results:
  630.  *    
  631.  *
  632.  * Side effects:
  633.  *    May map additional VME address space into the kernel.
  634.  *    Other side effects depending on the ioctl call requested.
  635.  *
  636.  *----------------------------------------------------------------------
  637.  */
  638.  
  639. /* ARGSUSED */
  640. ENTRY ReturnStatus
  641. DevXbusIOControl (devicePtr, ioctlPtr, replyPtr)
  642.     Fs_Device *devicePtr;        /* Information about device. */
  643.     register Fs_IOCParam *ioctlPtr;    /* Parameter information (buffer sizes
  644.                      * etc.). */
  645.     register Fs_IOReply *replyPtr;    /* Place to store result information.*/
  646. {
  647.     DevXbusCtrlRegs    *regPtr;
  648.     DevXbusInfo        *infoPtr;
  649.     int            inSize, outSize;
  650.     ReturnStatus    status = SUCCESS;
  651.     ReturnStatus    fmtStatus;
  652.     unsigned int    bufArray[DEV_XBUS_MAX_XOR_BUFS + 3];
  653.  
  654.     if ((infoPtr = (DevXbusInfo*)devicePtr->data) == NULL) {
  655.     return (DEV_INVALID_UNIT);
  656.     }
  657.     if (devXbusDebug) {
  658.     printf ("DevXbusIOControl: %s doing IOControl 0x%x\n",
  659.         infoPtr->name, ioctlPtr->command);
  660.     }
  661.  
  662.     regPtr = infoPtr->regs;
  663.  
  664.     switch (ioctlPtr->command) {
  665.       case IOC_XBUS_RESET:
  666.     status = DevXbusResetBoard (infoPtr);
  667.     break;
  668.       case IOC_XBUS_DEBUG_ON:
  669.     devXbusDebug = TRUE;
  670.     break;
  671.       case IOC_XBUS_DEBUG_OFF:
  672.     devXbusDebug = FALSE;
  673.     break;
  674.  
  675.       case IOC_XBUS_READ_REG:
  676.       case IOC_XBUS_WRITE_REG:
  677.     {
  678.         DevXbusRegisterAccess acc;
  679.         inSize = ioctlPtr->inBufSize;
  680.         outSize = sizeof (acc);
  681.         fmtStatus = Fmt_Convert ("ww", ioctlPtr->format, &inSize,
  682.                      ioctlPtr->inBuffer, mach_Format,
  683.                      &outSize, (Address)&acc);
  684.         if ((fmtStatus != FMT_OK) ||
  685.         (ioctlPtr->outBufSize < sizeof (acc))) {
  686.         printf ("Format of xbus register access failed, 0x%x\n",
  687.             fmtStatus);
  688.         status = GEN_INVALID_ARG;
  689.         goto ioctlExit;
  690.         }
  691.         status = accessXbusRegister (infoPtr,acc.registerNum,&(acc.value),
  692.                      ioctlPtr->command);
  693.         inSize = outSize = sizeof (acc);
  694.         fmtStatus = Fmt_Convert ("ww", mach_Format, &inSize,
  695.                      (Address)&acc, ioctlPtr->format,
  696.                      &outSize, (Address)ioctlPtr->outBuffer);
  697.         if (fmtStatus != FMT_OK) {
  698.         printf ("Format of xbus register access output failed, 0x%x\n",
  699.             fmtStatus);
  700.         status = GEN_INVALID_ARG;
  701.         goto ioctlExit;
  702.         }
  703.     }
  704.     break;
  705.  
  706.       case IOC_XBUS_DO_XOR:
  707.     {
  708.         int            numBufs;
  709.  
  710.         inSize = ioctlPtr->inBufSize;
  711.         outSize = sizeof (numBufs);
  712.         fmtStatus = Fmt_Convert ("w", ioctlPtr->format, &inSize,
  713.                      ioctlPtr->inBuffer, mach_Format,
  714.                      &outSize, (Address)&numBufs);
  715.         if (fmtStatus != FMT_OK) {
  716.         printf ("Format of IOC_XBUS_DO_XOR size field failed, 0x%x\n",
  717.             fmtStatus);
  718.         status = GEN_INVALID_ARG;
  719.         goto ioctlExit;
  720.         }
  721.         if (numBufs > DEV_XBUS_MAX_XOR_BUFS) {
  722.         status = GEN_INVALID_ARG;
  723.         goto ioctlExit;
  724.         }
  725.         inSize = ioctlPtr->inBufSize - sizeof (numBufs);
  726.         outSize = (numBufs + 2) * sizeof (bufArray[0]);
  727.         fmtStatus = Fmt_Convert ("www*", ioctlPtr->format, &inSize,
  728.                      (char*)ioctlPtr->inBuffer+sizeof(numBufs),
  729.                      mach_Format, &outSize,
  730.                      (Address)&(bufArray[0]));
  731.         if (fmtStatus != FMT_OK) {
  732.         printf ("Format of IOC_XBUS_DO_XOR parms failed, 0x%x\n",
  733.             fmtStatus);
  734.         status = GEN_INVALID_ARG;
  735.         goto ioctlExit;
  736.         }
  737.         if (devXbusDebug) {
  738.         int i;
  739.         printf ("%s doing XOR of: %d buffers, size=0x%x dst=0x%x\n",
  740.             infoPtr->name, numBufs, bufArray[0], bufArray[1]);
  741.         for (i = 0; i < numBufs; i++) {
  742.             printf ("%s: src buffer %d is 0x%x\n", infoPtr->name, i,
  743.                 bufArray[i+2]);
  744.         }
  745.         printf ("IOC_XBUS_DO_XOR: %s queueing XOR.\n", infoPtr->name);
  746.         }
  747.         MASTER_LOCK (&(infoPtr->mutex));
  748.         infoPtr->state |= DEV_XBUS_STATE_XOR_TEST;
  749.         DevXbusXor (infoPtr, bufArray[1], numBufs, &(bufArray[2]),
  750.             bufArray[0], xorCallback, (ClientData)infoPtr);
  751.         if (devXbusDebug) {
  752.         printf ("IOC_XBUS_DO_XOR: %s waiting for completion.\n",
  753.             infoPtr->name);
  754.         }
  755.         Sync_MasterWait (&xorTestDone,&(infoPtr->mutex),TRUE);
  756.         MASTER_UNLOCK (&(infoPtr->mutex));
  757.         if (devXbusDebug) {
  758.         printf ("IOC_XBUS_DO_XOR: %s done.\n", infoPtr->name);
  759.         }
  760.     }
  761.     break;
  762.  
  763.       case IOC_XBUS_TEST_START:
  764.     {
  765.         unsigned int    testArgs[5];
  766.  
  767.         if (infoPtr->state & DEV_XBUS_STATE_TESTING) {
  768.         status = DEV_BUSY;
  769.         goto ioctlExit;
  770.         }
  771.         infoPtr->state |= DEV_XBUS_STATE_TESTING;
  772.         inSize = ioctlPtr->inBufSize;
  773.         outSize = sizeof (testArgs);
  774.         fmtStatus = Fmt_Convert ("w5", ioctlPtr->format, &inSize,
  775.                      ioctlPtr->inBuffer, mach_Format,
  776.                      &outSize, (Address)testArgs);
  777.         if (fmtStatus != FMT_OK) {
  778.         printf ("Format of IOC_XBUS_TEST_START args failed, 0x%x\n",
  779.             fmtStatus);
  780.         status = GEN_INVALID_ARG;
  781.         goto ioctlExit;
  782.         }
  783.         if (devXbusDebug) {
  784.         printf ("%s: starting test, args=0x%x 0x%x 0x%x 0x%x 0x%x\n",
  785.             infoPtr->name, testArgs[0], testArgs[1], testArgs[2],
  786.             testArgs[3], testArgs[4]);
  787.         }
  788.         DevXbusTestStart (testArgs[0], testArgs[1], testArgs[2],
  789.                   testArgs[3], testArgs[4]);
  790.     }
  791.     break;
  792.       case IOC_XBUS_TEST_STOP:
  793.     if (!(infoPtr->state & DEV_XBUS_STATE_TESTING)) {
  794.         status = GEN_FAILURE;
  795.         goto ioctlExit;
  796.     }
  797.     infoPtr->state &= ~DEV_XBUS_STATE_TESTING;
  798.     if (devXbusDebug) {
  799.         printf ("IOC_XBUS_TEST_STOP: stopping test for %s.\n",
  800.             infoPtr->name);
  801.     }
  802.     DevXbusTestStop ();
  803.     break;
  804.       case IOC_XBUS_TEST_STATS:
  805.     {
  806.         if (devXbusDebug) {
  807.         printf ("IOC_XBUS_TEST_STATS: getting test stats for %s.\n",
  808.             infoPtr->name);
  809.         }
  810.         if (ioctlPtr->outBufSize < DEV_XBUS_TEST_MAX_STAT_STR) {
  811.         status = GEN_INVALID_ARG;
  812.         goto ioctlExit;
  813.         }
  814.         
  815.         DevXbusTestStat (ioctlPtr->outBuffer);
  816.     }
  817.     break;
  818.  
  819.       case IOC_XBUS_CHECK_PARITY:
  820.     {
  821.         unsigned int parityOn;
  822.         unsigned int oldParity;
  823.  
  824.         inSize = ioctlPtr->inBufSize;
  825.         outSize = sizeof (parityOn);
  826.         fmtStatus = Fmt_Convert ("w", ioctlPtr->format, &inSize,
  827.                      ioctlPtr->inBuffer, mach_Format,
  828.                      &outSize, (Address)&parityOn);
  829.         if (fmtStatus != FMT_OK) {
  830.         printf ("Format of IOC_XBUS_CHECK_PARITY args failed, 0x%x\n",
  831.             fmtStatus);
  832.         status = GEN_INVALID_ARG;
  833.         goto ioctlExit;
  834.         }
  835.         oldParity =
  836.         ((infoPtr->resetValue & DEV_XBUS_RESETREG_CHECK_PARITY) != 0);
  837.         MASTER_LOCK (&(infoPtr->mutex));
  838.         if (parityOn) {
  839.         infoPtr->resetValue |= DEV_XBUS_RESETREG_CHECK_PARITY;
  840.         regPtr->reset = regPtr->reset | DEV_XBUS_RESETREG_CHECK_PARITY;
  841.         } else {
  842.         infoPtr->resetValue &= ~DEV_XBUS_RESETREG_CHECK_PARITY;
  843.         regPtr->reset =regPtr->reset & ~DEV_XBUS_RESETREG_CHECK_PARITY;
  844.         }
  845.         MASTER_UNLOCK (&(infoPtr->mutex));
  846.         if (ioctlPtr->outBufSize >= sizeof (oldParity)) {
  847.         outSize = ioctlPtr->outBufSize;
  848.         inSize = sizeof (oldParity);
  849.         fmtStatus = Fmt_Convert ("w", mach_Format, &inSize,
  850.                      (Address)&oldParity, ioctlPtr->format,
  851.                      &outSize, ioctlPtr->outBuffer);
  852.         }
  853.     }
  854.     break;
  855.       case IOC_XBUS | 10000:
  856.     {
  857.         unsigned int i, numToLoop, sreg, rreg, doprint;
  858.         unsigned int printMask = 0x80000000;
  859.         bcopy (ioctlPtr->inBuffer, &numToLoop, sizeof (numToLoop));
  860.         doprint = ((numToLoop & printMask) != 0);
  861.         numToLoop &= ~printMask;
  862.         for (i = 0; i < numToLoop; i++) {
  863.         sreg = infoPtr->regs->status;
  864.         rreg = infoPtr->regs->reset;
  865.         if ((sreg == rreg) && doprint) {
  866.             printf ("%s: status reg = reset reg = 0x%x\n",
  867.                 infoPtr->name, sreg);
  868.         }
  869.         }
  870.     }
  871.     break;
  872.       default:
  873.     status = GEN_NOT_IMPLEMENTED;
  874.     break;
  875.     }
  876.  
  877.   ioctlExit:
  878.     return (status);
  879. }
  880.  
  881. /***********************************************************************
  882.  *
  883.  * DevXbusIntr --
  884.  *
  885.  *    The interrupt handler for the xbus board driver.  Currently,
  886.  *    this just prints a message saying that an interrupt was
  887.  *    received.
  888.  *
  889.  ***********************************************************************
  890.  */
  891. ENTRY Boolean
  892. DevXbusIntr (data)
  893. ClientData    data;
  894. {
  895.     DevXbusInfo*    infoPtr = (DevXbusInfo*)data;
  896.     unsigned int    boardStatus;
  897.     void         (*callbackProc)();
  898.     ReturnStatus    callStatus;
  899.     ClientData        clientData;
  900.     DevXbusXorInfo*    xorPtr;
  901.     unsigned int    tmp;
  902.  
  903.     boardStatus = infoPtr->regs->status;
  904.     if (devXbusDebug) {
  905.     printf ("DevXbusIntr: %s got interrupt, status = 0x%x\n",
  906.         infoPtr->name, boardStatus);
  907.     }
  908.  
  909.     if (boardStatus & DEV_XBUS_STATUS_XOR_INTERRUPT) {
  910.     if (devXbusDebug) {
  911.         printf ("DevXbusIntr: %d in XOR queue for %s.\n", infoPtr->numInQ,
  912.             infoPtr->name);
  913.     }
  914.     tmp = infoPtr->regs->reset;
  915.     if ((tmp & 0xb) != 0xb) {
  916.         /*
  917.          * Reset register messed up!
  918.          */
  919.         infoPtr->regs->reset = infoPtr->resetValue;
  920.         printf ("%s: DevXbusIntr found bad reset value (0x%x\n)",
  921.             infoPtr->name, tmp);
  922.     } else {
  923.         infoPtr->regs->reset = tmp & ~DEV_XBUS_RESETREG_CLEAR_XOR_BIT;
  924.         infoPtr->regs->reset = tmp | DEV_XBUS_RESETREG_CLEAR_XOR_BIT;
  925.     }
  926.     
  927.     if (infoPtr->numInQ > 0) {
  928.         MASTER_LOCK (&(infoPtr->mutex));
  929.         infoPtr->state &= ~DEV_XBUS_STATE_XOR_GOING;
  930.         xorPtr = infoPtr->qHead;
  931.         callbackProc = xorPtr->callbackProc;
  932.         clientData = xorPtr->clientData;
  933.         callStatus = SUCCESS;
  934.         infoPtr->qHead += 1;
  935.         if (infoPtr->qHead == infoPtr->qEnd) {
  936.         infoPtr->qHead = infoPtr->xorQueue;
  937.         }
  938.         infoPtr->numInQ -= 1;
  939.         DevXbusStuffXor (infoPtr);
  940.         MASTER_UNLOCK (&(infoPtr->mutex));
  941.         (callbackProc)(clientData, callStatus);
  942.     } else {
  943.         printf ("DevXbusIntr: %s got XOR intr with none outstanding.\n",
  944.             infoPtr->name);
  945.     }
  946.     } else if (boardStatus & (DEV_XBUS_STATUS_ATC0_PARITY_ERR ||
  947.                   DEV_XBUS_STATUS_ATC1_PARITY_ERR ||
  948.                   DEV_XBUS_STATUS_ATC2_PARITY_ERR ||
  949.                   DEV_XBUS_STATUS_ATC3_PARITY_ERR ||
  950.                   DEV_XBUS_STATUS_SERVER_PARITY_ERR)) {
  951.     printf ("DevXbusIntr: %s has parity error (status reg = 0x%x)!!\n",
  952.         infoPtr->name, boardStatus);
  953.     } else {
  954.     printf ("DevXbusIntr: %s got unknown interrupt (status reg = 0x%x)\n",
  955.         infoPtr->name, boardStatus);
  956.     }
  957.     return (TRUE);
  958. }
  959.  
  960. /*----------------------------------------------------------------------
  961.  *
  962.  * DevXbusOpen --
  963.  *
  964.  *    Open the xbus device.  All we want to do is make sure that
  965.  *    the device exists, and to insert an appropriate value into
  966.  *    the devicePtr->data field.
  967.  *
  968.  * Returns:
  969.  *    Standard Sprite return status.
  970.  * Side effects:
  971.  *    Modifies the devicePtr->data field.
  972.  *
  973.  *----------------------------------------------------------------------
  974.  */
  975. ENTRY ReturnStatus
  976. DevXbusOpen (devicePtr, useFlags, notifyToken, flagsPtr)
  977. Fs_Device    *devicePtr;
  978. int        useFlags;
  979. Fs_NotifyToken    notifyToken;
  980. int        *flagsPtr;
  981. {
  982.     if (devXbusDebug) {
  983.     printf ("DevXbusOpen: Trying to open unit %d\n", devicePtr->unit);
  984.     }
  985.     
  986.     if (devicePtr->unit >= DEV_XBUS_MAX_BOARDS) {
  987.     return (DEV_INVALID_UNIT);
  988.     }
  989.  
  990.     devicePtr->data = (ClientData)(xbusInfo[devicePtr->unit]);
  991.  
  992.     if (devicePtr->data == NULL) {
  993.     return (DEV_INVALID_UNIT);
  994.     }
  995.     if (devXbusDebug) {
  996.     printf ("DevXbusOpen: Opened device %s successfully (unit %d).\n",
  997.         ((DevXbusInfo*)devicePtr->data)->name, devicePtr->unit);
  998.     }
  999.  
  1000.     return (SUCCESS);
  1001. }
  1002.